/*
* Licensed under the MIT License
* 
* Copyright (c) 2010 Kay Kreuning
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package nl.hyves.api.rpc
{
	/**
	 * Decoded XML into Flash Object's.
	 * The decoder is built specifically to work with the Hyves API.
	 * 
	 * @author Kay Kreuning
	 */
	public final class XMLDecoder
	{
		private static const TEXT:String = "text";
		private static const ELEMENT:String = "element";
		
		/**
		 * Decode XML into a generic Flash Object, only nodes will be preserved, attributes in the XML are omitted.
		 * 
		 * @param xml XML to decode into a Flash Object
		 * @return decoded Object
		 */ 
		public static function decode(xml:XML):Object
		{
			if (xml == null) return null;
			
			var result:Object;
			var isSimpleType:Boolean = false;
			
			var children:XMLList = xml.children();
			
			if (children.length() == 1 && children[0].nodeKind() == TEXT)
			{
				// If exactly one text node subtype, we must want a simple value.
				isSimpleType = true;
				result = simpleType(children[0].valueOf())
			}
			else if (children.length() > 0)
			{
				result = {};
				
				for (var i:int = 0; i < children.length(); i++)
				{
					var partNode:XML = children[i];
					
					// Skip text nodes, which are part of mixed content
					if (partNode.nodeKind() != ELEMENT)
					{
						continue;
					}
					
					var partName:String = partNode.name();
					var partObj:Object = decode(partNode);
					
					// Enable processing multiple copies of the same element (sequences)
					var existing:Object = result[partName];
					if (existing != null)
					{
						if (existing is Array)
						{
							existing.push(partObj);
						}
						else
						{
							existing = [existing];
							existing.push(partObj);
							
							result[partName] = existing;
						}
					}
					else
					{
						result[partName] = partObj;
					}
				}
			}
			
			return result;
		}
		
		private static function simpleType(val:Object):Object
		{
			var result:Object = val;
			
			if (val != null)
			{
				// return the value as a string, a boolean or a number.
				// numbers that start with 0 are left as strings
				if (val is String && String(val) == "")
				{
					result = val.toString();
				}
				else if (isNaN(Number(val)) || (val.charAt(0) == "0") || ((val.charAt(0) == "-") && (val.charAt(1) == "0")) || val.charAt(val.length - 1) == "E")
				{
					var valStr:String = val.toString();
					
					var valStrLC:String = valStr.toLowerCase();
					
					if (valStrLC == "true")
						result = true;
					else if (valStrLC == "false")
						result = false;
					else
						result = valStr;
				}
				else
				{
					result = Number(val);
				}
			}
			
			return result;
		}
	}
}